Extents
*******

An extent is a region of text (a start position and an end position) that is displayed in a particular face and can have certain other properties such as being read-only.  Extents can overlap each other.  XEmacs efficiently handles buffers with large numbers of extents in them.

 -- Function: extentp object
     This returns t if OBJECT is an extent.

Introduction to Extents
=======================

An extent is a region of text within a buffer that has certain properties associated with it.  The properties of an extent primarily affect the way the text contained in the extent is displayed.  Extents can freely overlap each other in a buffer.  Extents are invisible to functions that merely examine the text of a buffer.

An extent is logically a Lisp object consisting of a start position, an end position, a buffer to which these positions refer, and a property list.  As text is inserted into the buffer, the start and end positions of the extent are automatically adjusted as necessary to keep the extent referring to the same text in the buffer.  If text is inserted at the boundary of an extent, the extent's start-open and end-open properties control whether the text is included as part of the extent.  If the text bounded by an extent is deleted, the extent becomes detached; its start and end positions are no longer meaningful, but it maintains all its other properties and can later be reinserted into a buffer.

Each extent has a face associated with it, which controls the way in which the text bounded by the extent is displayed .  If an extent's face is nil or its properties are partially undefined, the corresponding properties from the default face for the frame is used. If two or more extents overlap, the corresponding faces are merged to determine the text's displayed properties.  Every extent has a priority that determines which face takes precedence if the faces conflict. (If two extents have the same priority, the one that comes later in the display order takes precedence.  See display order.) Higher-numbered priority values correspond to a higher priority, and priority values can be negative.  Every extent is created with a priority of 0, but this can be changed with set-extent-priority.

Extents can be set to respond specially to key and mouse events within the extent.  An extent's keymap property controls the effect of key and mouse strokes within the extent's text, and the highlight property controls whether the extent is highlighted when the mouse moves over it.  See Extents and Events.

An extent can optionally have a start-glyph or end-glyph (but not both at one time) associated with it.  A start-glyph or end-glyph is a pixmap or string that will be displayed either at the start or end of an extent or in the margin of the line that the start or end of the extent lies in, depending on the extent's layout policy. Start-glyphs and end-glyphs are used to implement annotations, and you should use the annotation API functions in preference to the lower-level extent functions.  For more information, see Annotations.

If an extent has its detachable property set, it will become detached (i.e. no longer in the buffer) when all its text its deleted.  Otherwise, it will simply shrink down to zero-length and sit it the same place in the buffer.  By default, the detachable property is set on newly-created extents.  See Detached Extents.

If an extent has its duplicable property set, it will be remembered when a string is created from text bounded by the extent. When the string is re-inserted into a buffer, the extent will also be re-inserted.  This mechanism is used in the kill, yank, and undo commands.  See Duplicable Extents.

Creating and Modifying Extents
==============================

 -- Function: make-extent from to &optional buffer
     This function makes an extent for the range [FROM, TO) in BUFFER.  BUFFER defaults to the current buffer.  Insertions at point TO will be outside of the extent; insertions at FROM will be inside the extent, causing the extent to grow (see Extent Endpoints).  This is the same way that markers behave. The extent is initially detached if both FROM and TO are nil, and in this case BUFFER defaults to nil, meaning the extent is in no buffer (see Detached Extents).

 -- Function: delete-extent extent
     This function removes EXTENT from its buffer and destroys it. This does not modify the buffer's text, only its display properties. The extent cannot be used thereafter.  To remove an extent in such a way that it can be re-inserted later, use detach-extent. See Detached Extents.

 -- Function: extent-buffer extent
     This function returns the buffer of EXTENT.  If the return value is nil, this means that the extent is detached; however, a detached extent will not necessarily return a value of nil.

 -- Function: extent-live-p extent
     This function returns nil if EXTENT is deleted, and t otherwise.

Extent Endpoints
================

Every extent has a start position and an end position, and logically affects the characters between those positions.  Normally the start and end positions must both be valid positions in the extent's buffer. However, both endpoints can be nil, meaning the extent is detached.  See Detached Extents.

Whether the extent overlaps its endpoints is governed by its start-open and end-open properties.  Insertion of a character at a closed endpoint will expand the extent to include that character; insertion at an open endpoint will not.  Similarly, functions such as extent-at that scan over all extents overlapping a particular position will include extents with a closed endpoint at that position, but not extents with an open endpoint.

Note that the start-closed and end-closed properties are equivalent to start-open and end-open with the opposite sense.

Both endpoints can be equal, in which case the extent includes no characters but still exists in the buffer.  Zero-length extents are used to represent annotations (see Annotations) and can be used as a more powerful form of a marker.  Deletion of all the characters in an extent may or may not result in a zero-length extent; this depends on the detachable property (see Detached Extents).  Insertion at the position of a zero-length extent expands the extent if both endpoints are closed; goes before the extent if it has the start-open property; and goes after the extent if it has the end-open property.  Zero-length extents with both the start-open and end-open properties are not allowed to exist because there is no sensible way to define their properties.  (If all the text in an extent with both properties set is deleted and the extent is not detachable, the start-open property is removed from the extent.) Deletion of a character on a side of a zero-length extent whose corresponding endpoint is closed causes the extent to be detached if its detachable property is set; if the corresponding endpoint is open, the extent remains in the buffer, moving as necessary.

Extents are ordered within a buffer by increasing start position, and then by decreasing end position (this is called the display order).

 -- Function: extent-start-position extent
     This function returns the start position of EXTENT.

 -- Function: extent-end-position extent
     This function returns the end position of EXTENT.

 -- Function: extent-length extent
     This function returns the length of EXTENT in characters.  If the extent is detached, this returns 0.  If the extent is not detached, this is equivalent to

          (- (extent-end-position EXTENT) (extent-start-position EXTENT))

 -- Function: set-extent-endpoints extent start end
     This function sets the start and end position of EXTENT to START and END.  If both are nil, this is equivalent to detach-extent.

Finding Extents
===============

The following functions allow for scanning over the extents in a buffer or searching for extents in a particular range of a buffer.  Keep in mind the way that extents are ordered in a buffer (see Extent Endpoints).

 -- Function: next-extent extent
     Given an extent EXTENT, this function returns the next extent in the buffer's display order.  If EXTENT is a buffer, this returns the first extent in the buffer.

 -- Function: previous-extent extent
     Given an extent EXTENT, this function returns the previous extent in the buffer's display order.  If EXTENT is a buffer, this returns the last extent in the buffer.

If you want to map over all extents that meet a certain criterion, use map-extents -- it is much faster than a loop involving next-extent.

 -- Function: extent-at pos &optional buffer property before
     This function finds the ``smallest'' extent (i.e., the last one in the display order) at (i.e., overlapping) POS in BUFFER having PROPERTY set.  BUFFER defaults to the current buffer. PROPERTY defaults to nil, meaning that any extent will do. Returns nil if there is no matching extent at POS.  If the fourth argument BEFORE is not nil, it must be an extent; any returned extent will precede that extent.  This feature allows extent-at to be used by a loop over extents.

 -- Function: map-extents function &optional buffer from to maparg closed-end
     This function maps FUNCTION over the extents which overlap the region [FROM, TO) (or [FROM, TO] if CLOSED-END is non-nil) in BUFFER.  FUNCTION is called with the arguments (extent, MAPARG).  The arguments FROM, TO, MAPARG, and BUFFER default to the beginning of BUFFER, the end of BUFFER, nil, and (current-buffer), respectively.  map-extents returns the first non-nil result produced by FUNCTION, and no more calls to FUNCTION are made after that.  If BUFFER is an extent, FROM and TO default to the extent's endpoints, and the mapping omits that extent and its predecessors.  This feature supports restarting a loop based on map-extents.

     The effect of CLOSED-END is that, if an extent and the map region overlap only at a start and end position, the extent is visited by map-extents only if both positions are closed.

 -- Function: map-extent-children function &optional buffer from to maparg closed-end
     This function is similar to map-extents, but differs in that:

       * It only visits extents which start in the given region.

       * After visiting an extent E, it skips all other extents which start inside E but end before E's end.

     Thus, this function may be used to walk a tree of extents in a buffer:

          (defun walk-extents (buffer &optional ignore)
            (map-extent-children 'walk-extents buffer))

 -- Function: extent-in-region-p extent &optional from to closed-end
     This function returns T if map-extents would visit EXTENT if called with the given arguments.

Properties of Extents
=====================

Each extent has a property list associating property names with values. Some property names have predefined meanings, and can usually only assume particular values.  Assigning other values to such a property either cause the value to be converted into a legal value (e.g., assigning anything but nil to a Boolean property will cause the value of t to be assigned to the property) or will cause an error.  Property names without predefined meanings can be assigned any value.  An undefined property is equivalent to a property with a value of nil, or with a particular default value in the case of properties with predefined meanings.  Note that, when an extent is created, the end-open and detachable properties are set on it.

 -- Function: extent-property extent property
     This function returns the value of PROPERTY in EXTENT.  If PROPERTY is undefined, nil is returned.

 -- Function: extent-properties extent
     This function returns a list of all of EXTENT's properties that do not have the value of nil (or the default value, for properties with predefined meanings).

 -- Function: set-extent-property extent property value
     This function sets PROPERTY to VALUE in EXTENT. (If PROPERTY has a predefined meaning, only certain values are allowed, and some values may be converted to others before being stored.)

The following table lists the properties with predefined meanings, along with their allowable values.

detached
     (Boolean) Whether the extent is detached.   Setting this is the same as calling detach-extent.  See Detached Extents.

destroyed
     (Boolean) Whether the extent has been deleted.  Setting this is the same as calling delete-extent.

priority
     (integer) The extent's redisplay priority.  Defaults to 0.  See priority.  This property can also be set with set-extent-priority and accessed with extent-priority.

start-open
     (Boolean) Whether the start position of the extent is open, meaning that characters inserted at that position go outside of the extent. See Extent Endpoints.

start-closed
     (Boolean) Same as start-open but with the opposite sense.  Setting this property clears start-open and vice-versa.

end-open
     (Boolean) Whether the end position of the extent is open, meaning that characters inserted at that position go outside of the extent.  This is t by default. See Extent Endpoints.

end-closed
     (Boolean) Same as end-open but with the opposite sense.  Setting this property clears end-open and vice-versa.

read-only
     (Boolean) Whether text within this extent will be unmodifiable.

face
     (face, face name, or nil) The face in which to display the extent's text.  This property can also be set with set-extent-face and accessed with extent-face.

highlight
     (Boolean) Whether to highlight the extent when the mouse moves over it. See Extents and Events.

detachable
     (Boolean) Whether this extent becomes detached when all of the text it covers is deleted.  This is t by default.  See Detached Extents.

duplicable
     (Boolean) Whether this extent should be copied into strings, so that kill, yank, and undo commands will restore or copy it.  See Duplicable Extents.

unique
     (Boolean) Meaningful only in conjunction with duplicable.  When this is set, there may be only one instance of this extent attached at a time.  See Duplicable Extents.

invisible
     (Boolean) If t, text under this extent will not be displayed -- it will look as if the text is not there at all.

keymap
     (keymap or nil) This keymap is consulted for mouse clicks on this extent or keypresses made while point is within the extent. See Extents and Events.

copy-function
     This is a hook that is run when a duplicable extent is about to be copied from a buffer to a string (or the kill ring).  See Duplicable Extents.

paste-function
     This is a hook that is run when a duplicable extent is about to be copied from a string (or the kill ring) into a buffer.  See Duplicable Extents.

glyph-layout
     ('text, 'whitespace, 'inside-margin, or 'outside-margin) The layout policy for this extent's glyph.  Defaults to text. See Annotations.

begin-glyph
     (pixmap, string, or nil) This extent's begin-glyph.  Cannot be non-nil at the same time as end-glyph. See Annotations.

end-glyph
     (pixmap, string, or nil) This extent's end-glyph.  Cannot be non-nil at the same time as begin-glyph. See Annotations.

The following convenience functions are provided for accessing particular properties of an extent.

 -- Function: extent-priority extent
     This function returns the priority property of EXTENT.

 -- Function: extent-face extent
     This function returns the face property of EXTENT.

 -- Function: extent-layout extent
     This function returns the glyph-layout property of EXTENT.

 -- Function: extent-glyph extent
     This function returns the glyph associated with EXTENT.  This is the value of the begin-glyph or end-glyph property, if either one is non-nil. (It is not possible for both to be non-nil at the same time.)

The following convenience functions are provided for setting particular properties of an extent.

 -- Function: set-extent-priority extent pri
     This function sets the priority property of EXTENT to PRI.

 -- Function: set-extent-face extent face
     This function sets the face property of EXTENT to FACE.

 -- Function: set-extent-layout extent layout
     This function sets the glyph-layout property of EXTENT to LAYOUT.

 -- Function: set-extent-begin-glyph extent begin-glyph &optional layout
     This function sets the begin-glyph and glyph-layout properties of EXTENT to BEGIN-GLYPH and LAYOUT, respectively. (LAYOUT defaults to text if not specified.) This function will fail if EXTENT already has an END-GLYPH property.

 -- Function: set-extent-end-glyph extent end-glyph &optional layout
     This function sets the end-glyph and glyph-layout properties of EXTENT to END-GLYPH and LAYOUT, respectively. (LAYOUT defaults to text if not specified.) This function will fail if EXTENT already has a BEGIN-GLYPH property.

Detached Extents
================

A detached extent is an extent that is not attached to a buffer but can be re-inserted.  Detached extents have a start position and end position of nil.  Extents can be explicitly detached using detach-extent.  An extent is also detached when all of its characters are all killed by a deletion, if its detachable property is set; if this property is not set, the extent becomes a zero-length extent. (Zero-length extents with the detachable property set behave specially.  See zero-length extents.)

 -- Function: detach-extent extent
     This function detaches EXTENT from its buffer.  If EXTENT has the duplicable property, its detachment is tracked by the undo mechanism.  See Duplicable Extents.

 -- Function: extent-detached-p extent
     This function returns nil if EXTENT is detached, and t otherwise.

 -- Function: copy-extent extent &optional buffer
     This function makes a copy of EXTENT.  It is initially detached. Optional argument BUFFER defaults to EXTENT's buffer.

 -- Function: insert-extent extent &optional start end no-hooks
     This function inserts EXTENT from START to END in the current buffer.  If EXTENT is detached from a different buffer, or in most cases when EXTENT is already attached, the extent will first be copied as if with copy-extent.  This function operates the same as if insert were called on a string whose extent data calls for EXTENT to be inserted, except that if NO-HOOKS is non-nil, EXTENT's paste-function will not be invoked.  See Duplicable Extents.

Duplicable Extents
==================

If an extent has the duplicable property, it will be copied into strings, so that kill, yank, and undo commands will restore or copy it. Note that the extent is not actually copied; rather, a pointer to it is stored, along with the start and end positions of the extent. (This combination is called an extent replica.) This means that, e.g., if you copy a duplicable extent into the kill ring, then change the properties of the extent, then paste the kill-ring text back into the buffer, the newly-inserted extent will have the property changes you just made to the original extent, and not the property values at the time the text was copied into the kill ring.

Specifically:

  * When a string is created using buffer-substring or buffer-string, any duplicable extents in the region corresponding to the string will be remembered in the string (see Buffer Contents).  When the string in inserted into a buffer using insert, insert-before-markers, insert-buffer or insert-buffer-substring, the remembered extents will be inserted back into the buffer (see Insertion).  The extents can also be retrieved explicitly using string-extent-data (see Extent Replicas).

  * Similarly, when text is copied or cut into the kill ring, any duplicable extents will be remembered and reinserted later when the text is pasted back into a buffer.

  * An extent replica consists of a pointer to an extent and a range within the string.  When an extent replica is inserted into a buffer:

       - If the original extent was detached from this buffer, it is reattached at the new range.

       - If the original extent is attached to this buffer and is contiguous with or overlaps the new range, it is simply extended to include that range. Note that in this case the extent's paste-function is not called (see below).

       - If the original extent was detached from another buffer, it is copied as if by copy-extent and attached at the new range.

       - If the original extent is attached to another buffer, or is attached to this buffer and does not overlap the new range, it is copied as if by copy-extent and attached at the new range.  However, if the extent has the unique property, this action is inhibited and nothing happens.

  * When concat is called on strings, the extent replicas remembered in the strings are merged together and placed into the resulting string.

  * When substring is called on a string, the relevant extent replicas are placed into the resulting string.

  * When a duplicable extent is detached by detach-extent or string deletion, or inserted by insert-extent or string insertion, the action is recorded by the undo mechanism so that it can be undone later.

  * Extent motion, face changes, and attachment via make-extent are not recorded by the undo mechanism.  This means that extent changes which are to be undo-able must be performed by character editing, or by insertion and detachment of duplicable extents.

  * A duplicable extent's copy-function property, if non-nil, should be a function, and will be run when a duplicable extent is about to be copied from a buffer to a string (or the kill ring).  It is called with three arguments: the extent and the buffer positions within it which are being copied.  If this function returns nil, then the extent will not be copied; otherwise it will.

  * A duplicable extent's paste-function property, if non-nil, should be a function, and will be run when a duplicable extent is about to be copied from a string (or the kill ring) into a buffer.  It is called with three arguments: the original extent and the buffer positions which the copied extent will occupy. (This hook is run after the corresponding text has already been inserted into the buffer.) Note that the extent argument may be detached when this function is run.  If this function returns nil, no extent will be inserted. Otherwise, there will be an extent covering the range in question.

     Note: if the extent to be copied is already attached to the buffer and overlaps the new range, the extent will simply be extended and the paste-function will not be called.

Extent Replicas
===============

The following primitives for manipulating extent replicas are available. An extent replica is used to store extent data in a string and is a primitive data type encapsulating an extent and start and end positions within the string.  New extent replicas can be created but there are no mutator functions for modifying existing extent replicas. See Duplicable Extents.

Note: Lisp-visible extent replicas may disappear in the future (replaced by allowing map-extents to take a string argument).  Avoid using the following functions if at all possible.

 -- Function: extent-replica-p object
     This function returns non-nil if OBJECT is an extent replica.

 -- Function: extent-replica-live-p object
     This function returns non-nil if OBJECT is an extent replica that has not been deleted.

 -- Function: string-extent-data string
     This function returns the extent data stored along with STRING. The value returned is a list of extent replica objects.

 -- Function: set-string-extent-data string data
     This function sets the extent data stored along with a string. data should be nil or a list of extent replicas.

 -- Function: make-extent-replica extent start end
     This function makes an extent replica for EXTENT in the range from start to end.

 -- Function: extent-replica-extent dup
     This function returns the extent to which extent replica DUP refers.

 -- Function: extent-replica-start dup
     This function returns the start position of extent replica DUP.

 -- Function: extent-replica-end dup
     This function returns the end position of extent replica DUP.

Interaction of Extents with Keyboard and Mouse Events
=====================================================

If an extent has the highlight property set, it will be highlighted when the mouse passes over it.  Highlighting is accomplished by merging the extent's face with the highlight face.  The effect is as if a pseudo-extent with the highlight face were inserted after the extent in the display order (see Extent Endpoints, display order).

 -- Variable: mouse-highlight-priority
     This variable holds the priority to use when merging in the highlighting pseudo-extent.  The default is 1000.  This is purposely set very high so that the highlighting pseudo-extent shows up even if there are other extents with various priorities at the same location.

You can also explicitly cause an extent to be highlighted.  Only one extent at a time can be highlighted in this fashion, and any other highlighted extent will be de-highlighted.

 -- Function: highlight-extent extent &optional highlight-p
     This function highlights (if HIGHLIGHT-P is non-nil) or de-highlights (if HIGHLIGHT-P is nil) EXTENT, if EXTENT has the highlight property. (Nothing happens if EXTENT does not have the highlight property.)

 -- Function: force-highlight-extent extent &optional highlight-p
     This function is similar to highlight-extent but highlights or de-highlights the extent regardless of whether it has the highlight property.

If an extent has a keymap property, this keymap will be consulted for mouse clicks on the extent and keypresses made while point is within the extent.  The behavior of mouse clicks and keystrokes not defined in the keymap is as normal for the buffer.

Atomic Extents
==============

If the Lisp file atomic-extents is loaded, then the atomic extent facility is available.  An atomic extent is an extent for which point cannot be positioned anywhere within it.  This ensures that when selecting text, either all or none of the extent is selected.

To make an extent atomic, set its atomic property.